package com.scott.barmanager;

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Build;
import android.support.annotation.ColorInt;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;

public class BarManager {

    private static final int TYPE_COLOR = 1;
    private static final int TYPE_TRANSPARENT = 2;
    private static final int TYPE_IMMERSION = 3;
    private static final int TYPE_HIDE = 4;

    private Activity mActivity;
    private int mType;

    private ColorBuilder mColorBuilder;
    private HideBuilder mHideBuilder;
    private ImmersionBuilder mImmersionBuilder;

    private BarManager(Activity activity, ColorBuilder colorBuilder, int type) {
        mActivity = activity;
        mColorBuilder = colorBuilder;
        mType = type;
    }

    private BarManager(Activity activity, HideBuilder hideBuilder) {
        mActivity = activity;
        mHideBuilder = hideBuilder;
        mType = TYPE_HIDE;
    }

    public BarManager(Activity activity, ImmersionBuilder immersionBuilder) {
        mActivity = activity;
        mImmersionBuilder = immersionBuilder;
        mType = TYPE_IMMERSION;
    }

    public static ColorBuilder createColorBuilder() {
        return new ColorBuilder(TYPE_COLOR);
    }

    public static ColorBuilder createTransparentBuilder() {
        return new ColorBuilder(TYPE_TRANSPARENT);
    }

	public static ImmersionBuilder createImmersionBuilder() {
        return new ImmersionBuilder();
    }

    public static HideBuilder createHideBuilder() {
        return new HideBuilder();
    }

    public void modify() {
        if (mType == TYPE_COLOR) {
            setBarColor(mColorBuilder.statusColor, mColorBuilder.statusAlpha, mColorBuilder.modifyNavi, mColorBuilder.naviColor, mColorBuilder.naviAlpha);
        } else if (mType == TYPE_TRANSPARENT) {
            setBarTransparent(mColorBuilder.statusColor, mColorBuilder.statusAlpha, mColorBuilder.modifyNavi,
                    mColorBuilder.naviColor, mColorBuilder.naviAlpha);
        } else if (mType == TYPE_IMMERSION) {
            setBarTransparent(Color.TRANSPARENT, 0, mImmersionBuilder.modifyNavi, Color.TRANSPARENT, 0);
        } else if (mType == TYPE_HIDE) {
            setBarHide(mHideBuilder.modifyNavi);
        }
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    private void setBarHide(boolean modifyNavi) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            View decorView = mActivity.getWindow().getDecorView();
            int options = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    | View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
            if (modifyNavi) {
                options = options | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
            }
            decorView.setSystemUiVisibility(options);
        }
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    private void setBarTransparent(@ColorInt int statusColor, int statusAlpha, boolean modifyNavi, @ColorInt int naviColor, int naviAlpha) {
        Window window = mActivity.getWindow();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            View decorView = window.getDecorView();
            int options = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
            int statusColorValue = statusColor == 0 ? Color.TRANSPARENT : Color.argb(checkAlphaValue(statusAlpha), Color.red(statusColor), Color.green(statusColor), Color.blue(statusColor));
            window.setStatusBarColor(statusColorValue);

            if (modifyNavi) {
                options = options | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
                int naviColorColor = naviColor == 0 ? Color.TRANSPARENT : Color.argb(checkAlphaValue(naviAlpha), Color.red(naviColor), Color.green(naviColor), Color.blue(naviColor));
                window.setNavigationBarColor(naviColorColor);
            }
            decorView.setSystemUiVisibility(options);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            ViewGroup decorView = (ViewGroup) window.getDecorView();
            int statusColorValue = statusColor == 0 ? Color.TRANSPARENT : Color.argb(checkAlphaValue(statusAlpha), Color.red(statusColor), Color.green(statusColor), Color.blue(statusColor));
            decorView.addView(createStatusBarView(mActivity, statusColorValue));
            if (modifyNavi && naviBarExit(mActivity)) {
                window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
                int naviAlphaValue = naviColor == 0 ? Color.TRANSPARENT : Color.argb(Color.alpha(naviColor), Color.red(naviColor), Color.green(naviColor), Color.blue(naviColor));
                decorView.addView(createNaviBarView(mActivity, naviAlphaValue));
            }
        }
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    private void setBarColor(@ColorInt int statusColor, int statusAlpha, boolean modifyNavi, @ColorInt int naviColor, int naviAlpha) {
        int statusAlphaValue = checkAlphaValue(statusAlpha);
        Window window = mActivity.getWindow();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            int color = statusAlphaValue == 0 ? statusColor : calculateColor(statusColor, statusAlphaValue);
            window.setStatusBarColor(color);

            if (modifyNavi) {
                int naviAlphaValue = checkAlphaValue(naviAlpha);
                int navi = naviAlphaValue == 0 ? naviColor : calculateColor(naviColor, naviAlphaValue);
                window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
                window.setNavigationBarColor(navi);
            }
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            int color = statusAlphaValue == 0 ? statusColor : calculateColor(statusColor, statusAlphaValue);
            ViewGroup decor = (ViewGroup) window.getDecorView();
            decor.addView(createStatusBarView(mActivity, color));
            if (modifyNavi && naviBarExit(mActivity)) {
                int naviAlphaValue = checkAlphaValue(naviAlpha);
                int navi = naviAlphaValue == 0 ? naviColor : calculateColor(naviColor, naviAlphaValue);
                window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
                decor.addView(createNaviBarView(mActivity, navi));
            }
            setRootView(mActivity, true);
        }
    }

    private void setRootView(Activity activity, boolean fitSystemWindows) {
        ViewGroup parent = activity.findViewById(android.R.id.content);
        for (int i = 0; i < parent.getChildCount(); i++) {
            View child = parent.getChildAt(i);
            if (child instanceof ViewGroup) {
                child.setFitsSystemWindows(fitSystemWindows);
                ((ViewGroup) child).setClipToPadding(fitSystemWindows);
            }
        }


    }

    private boolean naviBarExit(Activity activity) {
        WindowManager windowManager = activity.getWindowManager();
        Display display = windowManager.getDefaultDisplay();
        DisplayMetrics metrics = new DisplayMetrics();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
            display.getRealMetrics(metrics);

        int h = metrics.heightPixels;
        int w = metrics.widthPixels;

        DisplayMetrics displayMetrics = new DisplayMetrics();
        display.getMetrics(displayMetrics);

        int displayH = displayMetrics.heightPixels;
        int displayW = displayMetrics.widthPixels;

        return (w - displayW) > 0 || (h - displayH) > 0;
    }

    private View createNaviBarView(Context context, @ColorInt int color) {
        View naviBarView = new View(context);
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, getNavigationBarHeight(context));
        params.gravity = Gravity.BOTTOM;
        naviBarView.setLayoutParams(params);
        naviBarView.setBackgroundColor(color);
        return naviBarView;
    }

    private int getNavigationBarHeight(Context context) {
        Resources resources = context.getResources();
        int resId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
        return resources.getDimensionPixelSize(resId);
    }

    private View createStatusBarView(Context context, @ColorInt int color) {
        View statusBar = new View(context);
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, getStatusBarHeight(context));
        params.gravity = Gravity.TOP;
        statusBar.setLayoutParams(params);
        statusBar.setBackgroundColor(color);
        return statusBar;
    }

    private int getStatusBarHeight(Context context) {
        Resources resources = context.getResources();
        int resId = resources.getIdentifier("status_bar_height", "dimen", "android");
        return resources.getDimensionPixelSize(resId);
    }

    @ColorInt
    private int calculateColor(@ColorInt int color, int alpha) {
        float a = 1 - alpha / 255f;
        int r = color >> 16 & 0xFF;
        int g = color >> 8 & 0xFF;
        int b = color & 0xFF;
        r = (int) (r * a + 0.5);
        g = (int) (g * a + 0.5);
        b = (int) (b * a + 0.5);
        return 0xFF << 24 | r << 16 | g << 8 | b;
    }

    private int checkAlphaValue(int alpha) {
        if (alpha < 0)
            return 0;
        if (alpha > 255)
            return 255;
        return alpha;
    }

    public static class ColorBuilder {

        @ColorInt
        private int statusColor;
        @ColorInt
        private int naviColor;

        private int statusAlpha = 0;
        private int naviAlpha = 0;
        private boolean modifyNavi = false;
        private int type;

        public ColorBuilder(int type) {
            this.type = type;
        }

        public ColorBuilder setStatusColor(@ColorInt int statusColor) {
            this.statusColor = statusColor;
            return this;
        }

        public ColorBuilder setStatusAlpha(int statusAlpha) {
            this.statusAlpha = statusAlpha;
            return this;
        }

        public ColorBuilder modifyNavi(boolean modifyNavi) {
            this.modifyNavi = modifyNavi;
            return this;
        }

        public ColorBuilder setNaviColor(@ColorInt int naviColor) {
            this.naviColor = naviColor;
            return this;
        }

        public ColorBuilder setNaviAlpha(int naviAlpha) {
            this.naviAlpha = naviAlpha;
            return this;
        }

        public BarManager build(Activity activity) {
            return new BarManager(activity, this, type);
        }
    }

    public static class HideBuilder {

        private boolean modifyNavi = false;

        public HideBuilder modifyNavi(boolean modifyNavi) {
            this.modifyNavi = modifyNavi;
            return this;
        }

        public BarManager build(Activity activity) {
            return new BarManager(activity, this);
        }
    }

    public static class ImmersionBuilder {

        private boolean modifyNavi = false;

        public ImmersionBuilder modifyNavi(boolean modifyNavi) {
            this.modifyNavi = modifyNavi;
            return this;
        }

        public BarManager build(Activity activity) {
            return new BarManager(activity, this);
        }
    }

}
